using System;
using System.Collections.Generic;
using Xunit;
using 詞法分析;
using 語法分析;

namespace ChineseCompiler.Tests
{
    /// <summary>
    /// 語法分析器測試類
    /// </summary>
    public class 語法分析測試
    {
        private List<詞法單元> 創建詞法單元列表(params (詞法單元類型 類型, string 值)[] 詞法單元數據)
        {
            var 列表 = new List<詞法單元>();
            for (int i = 0; i < 詞法單元數據.Length; i++)
            {
                var (類型, 值) = 詞法單元數據[i];
                列表.Add(new 詞法單元(類型, 值, 1, i + 1));
            }
            列表.Add(new 詞法單元(詞法單元類型.文件結束, "", 1, 詞法單元數據.Length + 1));
            return 列表;
        }
        
        [Fact]
        public void 測試變量聲明解析()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.吾有, "吾有"),
                (詞法單元類型.一數, "一數"),
                (詞法單元類型.曰, "曰"),
                (詞法單元類型.字符串, "甲"),
                (詞法單元類型.其值, "其值"),
                (詞法單元類型.數字, "三"),
                (詞法單元類型.也, "也")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            Assert.Single(程序.語句列表);
            Assert.IsType<變量聲明節點>(程序.語句列表[0]);
            
            var 變量聲明 = (變量聲明節點)程序.語句列表[0];
            Assert.Equal("一數", 變量聲明.變量類型);
            Assert.Equal("甲", 變量聲明.變量名稱);
            Assert.NotNull(變量聲明.初始值);
        }
        
        [Fact]
        public void 測試無初始值變量聲明()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.吾有, "吾有"),
                (詞法單元類型.一言, "一言"),
                (詞法單元類型.曰, "曰"),
                (詞法單元類型.字符串, "乙"),
                (詞法單元類型.也, "也")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            Assert.Single(程序.語句列表);
            var 變量聲明 = (變量聲明節點)程序.語句列表[0];
            Assert.Equal("一言", 變量聲明.變量類型);
            Assert.Equal("乙", 變量聲明.變量名稱);
            Assert.Null(變量聲明.初始值);
        }
        
        [Fact]
        public void 測試輸出語句解析()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.云, "云"),
                (詞法單元類型.字符串, "你好")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            Assert.Single(程序.語句列表);
            Assert.IsType<輸出語句節點>(程序.語句列表[0]);
            
            var 輸出語句 = (輸出語句節點)程序.語句列表[0];
            Assert.NotNull(輸出語句.輸出表達式);
            Assert.IsType<字面量表達式節點>(輸出語句.輸出表達式);
        }
        
        [Fact]
        public void 測試條件語句解析()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.若, "若"),
                (詞法單元類型.數字, "三"),
                (詞法單元類型.大於, "大於"),
                (詞法單元類型.數字, "二"),
                (詞法單元類型.者, "者"),
                (詞法單元類型.云, "云"),
                (詞法單元類型.字符串, "真"),
                (詞法單元類型.若非, "若非"),
                (詞法單元類型.云, "云"),
                (詞法單元類型.字符串, "假"),
                (詞法單元類型.云云, "云云")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            Assert.Single(程序.語句列表);
            Assert.IsType<條件語句節點>(程序.語句列表[0]);
            
            var 條件語句 = (條件語句節點)程序.語句列表[0];
            Assert.NotNull(條件語句.條件表達式);
            Assert.Single(條件語句.真分支);
            Assert.Single(條件語句.假分支);
        }
        
        [Fact]
        public void 測試無假分支條件語句()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.若, "若"),
                (詞法單元類型.數字, "一"),
                (詞法單元類型.者, "者"),
                (詞法單元類型.云, "云"),
                (詞法單元類型.字符串, "真"),
                (詞法單元類型.云云, "云云")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            var 條件語句 = (條件語句節點)程序.語句列表[0];
            Assert.Single(條件語句.真分支);
            Assert.Empty(條件語句.假分支);
        }
        
        [Fact]
        public void 測試循環語句解析()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.恆為是, "恆為是"),
                (詞法單元類型.云, "云"),
                (詞法單元類型.字符串, "循環中"),
                (詞法單元類型.云云, "云云")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            Assert.Single(程序.語句列表);
            Assert.IsType<循環語句節點>(程序.語句列表[0]);
            
            var 循環語句 = (循環語句節點)程序.語句列表[0];
            Assert.Single(循環語句.循環體);
        }
        
        [Fact]
        public void 測試二元運算表達式解析()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.云, "云"),
                (詞法單元類型.數字, "三"),
                (詞法單元類型.加, "加"),
                (詞法單元類型.數字, "五")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            var 輸出語句 = (輸出語句節點)程序.語句列表[0];
            Assert.IsType<二元運算表達式節點>(輸出語句.輸出表達式);
            
            var 二元運算 = (二元運算表達式節點)輸出語句.輸出表達式;
            Assert.Equal("加", 二元運算.運算符);
            Assert.IsType<字面量表達式節點>(二元運算.左操作數);
            Assert.IsType<字面量表達式節點>(二元運算.右操作數);
        }
        
        [Fact]
        public void 測試字面量表達式解析()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.云, "云"),
                (詞法單元類型.數字, "42")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            var 輸出語句 = (輸出語句節點)程序.語句列表[0];
            Assert.IsType<字面量表達式節點>(輸出語句.輸出表達式);
            
            var 字面量 = (字面量表達式節點)輸出語句.輸出表達式;
            Assert.Equal(詞法單元類型.數字, 字面量.類型);
        }
        
        [Fact]
        public void 測試標識符表達式解析()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.云, "云"),
                (詞法單元類型.標識符, "變量名")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            var 輸出語句 = (輸出語句節點)程序.語句列表[0];
            Assert.IsType<標識符表達式節點>(輸出語句.輸出表達式);
            
            var 標識符 = (標識符表達式節點)輸出語句.輸出表達式;
            Assert.Equal("變量名", 標識符.名稱);
        }
        
        [Fact]
        public void 測試多語句程序解析()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.吾有, "吾有"),
                (詞法單元類型.一數, "一數"),
                (詞法單元類型.曰, "曰"),
                (詞法單元類型.字符串, "甲"),
                (詞法單元類型.也, "也"),
                (詞法單元類型.云, "云"),
                (詞法單元類型.字符串, "甲")
            );
            
            // Act
            var 程序 = 分析器.分析(詞法單元列表);
            
            // Assert
            Assert.Equal(2, 程序.語句列表.Count);
            Assert.IsType<變量聲明節點>(程序.語句列表[0]);
            Assert.IsType<輸出語句節點>(程序.語句列表[1]);
        }
        
        [Fact]
        public void 測試語法錯誤拋出異常()
        {
            // Arrange
            var 分析器 = new 語法分析器();
            var 詞法單元列表 = 創建詞法單元列表(
                (詞法單元類型.吾有, "吾有"),
                (詞法單元類型.數字, "123") // 錯誤：期望類型但得到數字
            );
            
            // Act & Assert
            Assert.Throws<Exception>(() => 分析器.分析(詞法單元列表));
        }
    }
} 